﻿/*
 * SpotiFAG - Makes spotify ads less annoying
 * Copyright (C) 2010  ed <tripflag@gmail.com>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License v2
 * (version 2) as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, refer to the following URL:
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
 */
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace spotifag {
    public partial class Form1 : Form {

        public Form1() {
            InitializeComponent();
        }

        Spotify app;
        List<string> aids;
        string lastPlayed;
        NotifyIcon dicks;
        bool ad;

        private void Form1_Load(object sender, EventArgs e) {
            this.Icon = new Icon(embedded("spotifag.ico"));
            app = new Spotify();
            if (!app.lockedOn()) {

                // Did we find a spotify instance?
                System.Windows.Forms.MessageBox.Show(
                    "Start spotify first you DOUBLE NIGGER");
                System.Diagnostics.Process.GetCurrentProcess().Kill();
            }

            ad = false;
            lastPlayed = null;
            aids = new List<string>();
            if (!System.IO.File.Exists("aids.txt")) {
                
                // Download the aids.txt from GOOGLE COED WICKI
                string unicoed = Encoding.UTF8.GetString(new System.Net.WebClient()
                    .DownloadData("http://code.google.com/p/spotifag/wiki/ads"));
                
                // Extract the list of ads
                string[] hurrr = S.split(S.split(S.split(unicoed,
                    "<h1><a name=\"Details\"/>Details</h1><ul><li>")[1],
                    "</ul>")[0], "<li>");

                // Merge and save to aids.txt
                StringBuilder aidsman = new StringBuilder();
                foreach (string durrr in hurrr) {
                    aidsman.AppendLine(S.split(durrr, "</li>")[0]);
                }
                System.IO.File.WriteAllText("aids.txt", aidsman.ToString(), Encoding.UTF8);

                // Also, versioncheck.
                if (!unicoed.Contains("$" + Application.ProductVersion)) {
                    
                    // Query the user whether he wishes to update
                    if (DialogResult.Yes == MessageBox.Show(
                        "THERE HAS NEW VERSION, DO YOU WANT TO THE DOWNLOAD",
                        "hello there", MessageBoxButtons.YesNo)) {

                        // Navigate to GOOGLE COED to download new update
                        System.Diagnostics.Process.Start("http://code.google.com/p/spotifag/downloads/list");
                        System.Diagnostics.Process.GetCurrentProcess().Kill();
                    }
                }
            }

            // Load aids.txt to memory
            string[] penes = System.IO.File.ReadAllLines("aids.txt", Encoding.UTF8);
            foreach (string penis in penes) {
                g_lst.Items.Add(penis);
                aids.Add(penis);
            }

            Timer t = new Timer();
            t.Tick += new EventHandler(t_Tick);
            t.Interval = 100;
            t.Start();

            dicks = new NotifyIcon();
            dicks.Icon = this.Icon;
            dicks.Visible = true;
            dicks.MouseClick += new MouseEventHandler(dicks_MouseClick);
            dicks.Text = "Leftclick to show/hide, rightclick to ban ad";
        }

        // Tray icon click event handler
        void dicks_MouseClick(object sender, MouseEventArgs e) {
            
            // Toggle visibility on left
            if (e.Button == MouseButtons.Left) {
                if (this.Visible) {
                    // I can't believe the .NET framework doesn't have a managed way
                    // to smoothly minimize windows (with animations). 3/10 microsoft
                    this.WindowState = FormWindowState.Minimized;
                    this.Visible = false;
                } else {
                    this.Visible = true;
                    Application.DoEvents();
                    this.WindowState = FormWindowState.Normal;
                }
            }
            // Ban ad on right
            if (e.Button == MouseButtons.Right)
                g_ban_Click(sender, null);
        }

        // Read an embedded resource
        System.IO.Stream embedded(string filename) {
            return System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream("spotifag." + filename);
        }

        bool inTimer = false;
        void t_Tick(object sender, EventArgs e) {

            // Racing conditions? NOT ON MY SHIFT
            if (inTimer) return;
            inTimer = true;

            // Read track, compare to previous
            string t = app.track();
            string old = lastPlayed;
            lastPlayed = t;
            if (t != old) {
                
                // Changed song since last check
                g_tit.Text = t;
                if (t != null) {

                    // Is this an ad?
                    bool derp = hurrdurr(t);
                    g_tit.Text = !derp ? t :
                        "MOTHERFUCKING AD";

                    // Mute if this is an ad
                    // Unmute if it isn't
                    muter(derp);

                } else if (ad) {
                    //muter(false);
                    // I just got two subsequent ads which makes this code redundant as fuck
                }
            }
            inTimer = false;
        }

        // Check whether query is an ad
        Boolean hurrdurr(string query) {
            foreach (string str in aids) {
                if (str == query) return true;
            }
            return false;
        }

        // Adds current track as an ad
        private void g_ban_Click(object sender, EventArgs e) {
            wait(250);
            string cunt = app.track();
            if (hurrdurr(cunt)) {
                MessageBox.Show("hey bro there's no point in adding the same ad multiple times");
            } else {
                muter(true);
                g_lst.Items.Add(cunt);
                aids.Add(cunt);
            }
        }

        // Maybe this is crazy enough to actually work
        void wait(int i) {
            long a = S.ms();
            while (a + i > S.ms()) {
                Application.DoEvents();
            }
        }

        // Listens for [del] in the adlist (to remove ads)
        private void g_lst_KeyDown(object sender, KeyEventArgs e) {
            if (e.KeyCode == Keys.Delete) {
                int idx = g_lst.SelectedIndex;
                if (idx >= 0) {
                    g_lst.Items.RemoveAt(idx);
                    aids.RemoveAt(idx);
                }
            }
        }

        // Write the new aids.txt before exit
        private void Form1_FormClosing(object sender, FormClosingEventArgs e) {
            StringBuilder write = new StringBuilder();
            foreach (string ad in aids) {
                write.AppendLine(ad);
            }
            System.IO.File.WriteAllText("aids.txt", write.ToString(), Encoding.UTF8);
            dicks.Dispose();
        }

        // Keycode testan tool
        private void Form1_KeyDown(object sender, KeyEventArgs e) {
            this.Text = (int)e.KeyCode + " - " + e.KeyCode;
        }

        MP3 mp3;
        int lastFile = -1;
        Random rand = new Random();
        private void muter(bool mute) {
            
            // Will we mute/unmute?
            if (app.willToggle(mute)) {

                bool wait = g_wait.Checked;

                // fucking logics, how do they work
                /*  wait, ad: -s   +b
                 * !wait, ad: +b   -s
                 *  wait,!ad: -b W +s
                 * !wait,!ad: -b   +s
                 */
                
                // Incoming ad and mute first?
                if (wait && mute)

                    // Mute first.
                    app.mute(mute, g_fully.Checked);

                if (mute) {
                    // Play BGM
                    blaster();
                } else {
                    // Stop BGM
                    unblaster();
                }

                // Wait for fade?
                if (wait && !mute) {
                    while (mp3 != null && !mp3.fadeCompleted()) {
                        System.Threading.Thread.Sleep(1);
                        Application.DoEvents();
                    }
                }

                // Mute/unmute if we haven't already
                app.mute(mute, g_fully.Checked);
            }

            // The old mutan coed. A bit easier to read, ne?
            /*if (app.mute(mute, g_fully.Checked)) {
                if (mute) {
                    blaster();
                } else {
                    unblaster();
                }
            }*/
        }

        private void blaster() {

            // Do we have any bgm at all?
            if (!System.IO.Directory.Exists("res")) return;

            // Read the list of bgm files
            string[] files = System.IO.Directory.GetFiles("res");

            // Folder existed, files didn't
            if (files.Length == 0) return;
            int file;
            
            // Select a random file until it's not the one played last
            do {
                file = rand.Next(files.Length);
            } while (files.Length > 1 && file == lastFile);

            // Stop playing the previous file (if any)
            if (mp3 != null) mp3.close();

            // LET THERE BE MUSIC
            mp3 = new MP3(files[file], 1);
            lastFile = file;
            mp3.play();
        }
        private void unblaster() {
            if (mp3 != null) mp3.fadeOut();
        }

        private void Form1_Resize(object sender, EventArgs e) {
            if (this.WindowState == FormWindowState.Minimized) {
                // I hate doing hacks but I'm NOT adding another
                // pinvoke just to get smooth animations
                Application.DoEvents();
                System.Threading.Thread.Sleep(200);
                this.Visible = false;
            }
        }
    }
}